package org.firebug.common.tools.net;

import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.util.*;

public final class HttpTools {
    private static Logger logger = LoggerFactory.getLogger("third");

    private static String serialize(Map<?, ?> param) {
        List<String> params = new ArrayList<>(param.size());
        for (Map.Entry<?, ?> entry : param.entrySet()) {
            params.add(entry.getKey() + "=" + entry.getValue());
        }
        return StringUtils.collectionToDelimitedString(params, "&");
    }

    public static String get(String url) throws IOException {
        return get(url, null, null);
    }

    public static String get(String url, Map<?, ?> param) throws IOException {
        return get(url, null, param);
    }

    public static String get(String url, Map<String, String> header, Map<?, ?> param) throws IOException {
        if (param != null && !param.isEmpty()) {
            url = url + "?" + serialize(param);
        }
        logger.info("GET request: {}", url);
        Request.Builder builder = new Request.Builder();
        if (header != null && !header.isEmpty()) {
            for (Map.Entry<String, String> entry : header.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        Request request = builder.url(url).get().build();
        OkHttpClient client = new OkHttpClient().newBuilder().build();
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) {
            throw new IOException("GET request failure：" + url);
        }
        return response.body().string();
    }

    public static String post(String url, String json) throws IOException {
        return post(url, null, json);
    }

    public static String post(String url, Map<String, String> header, String json) throws IOException {
        logger.info("POST request: {}", url);
        Request.Builder builder = new Request.Builder();
        if (header != null && !header.isEmpty()) {
            for (Map.Entry<String, String> entry : header.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        RequestBody body = RequestBody.create(MediaType.parse("application/json"), json);
        Request request = builder.url(url).post(body).build();
        OkHttpClient client = new OkHttpClient().newBuilder().build();
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) {
            throw new IOException("POST request failure：" + url);
        }
        return response.body().string();
    }

    public static String put(String url, String json) throws IOException {
        return put(url, null, json);
    }

    public static String put(String url, Map<String, String> header, String json) throws IOException {
        logger.info("PUT request: {}", url);
        RequestBody body = RequestBody.create(MediaType.parse("application/json"), json);
        Request.Builder builder = new Request.Builder();
        if (header != null && !header.isEmpty()) {
            for (Map.Entry<String, String> entry : header.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        Request request = builder.url(url).put(body).build();
        OkHttpClient client = new OkHttpClient().newBuilder().build();
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) {
            throw new IOException("PUT request failure：" + url);
        }
        return response.body().string();
    }

    public static String delete(String url) throws IOException {
        return delete(url, null, null);
    }

    public static String delete(String url, Map<?, ?> param) throws IOException {
        return delete(url, null, param);
    }

    public static String delete(String url, Map<String, String> header, Map<?, ?> param) throws IOException {
        if (param != null && !param.isEmpty()) {
            url = url + "?" + serialize(param);
        }
        logger.info("DELETE request: {}", url);
        Request.Builder builder = new Request.Builder();
        if (header != null && !header.isEmpty()) {
            for (Map.Entry<String, String> entry : header.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        Request request = builder.url(url).delete().build();
        OkHttpClient client = new OkHttpClient().newBuilder().build();
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) {
            throw new IOException("DELETE request failure：" + url);
        }
        return response.body().string();
    }

    public static byte[] download(String url) throws IOException {
        return download(url, null, null);
    }

    public static byte[] download(String url, Map<?, ?> param) throws IOException {
        return download(url, null, param);
    }

    public static byte[] download(String url, Map<String, String> header, Map<?, ?> param) throws IOException {
        if (param != null && !param.isEmpty()) {
            url = url + "?" + serialize(param);
        }
        logger.info("download request: {}", url);
        Request.Builder builder = new Request.Builder();
        if (header != null && !header.isEmpty()) {
            for (Map.Entry<String, String> entry : header.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        Request request = builder.url(url).get().build();
        OkHttpClient client = new OkHttpClient().newBuilder().build();
        Response response = client.newCall(request).execute();
        if(!response.isSuccessful()) {
            throw new IOException("download file failure：" + url);
        }
        return response.body().bytes();
    }

    public static String upload(String url, Map<String, File[]> form) throws IOException {
        logger.info("upload request: {}", url);
        MultipartBody.Builder body = new MultipartBody.Builder().setType(MultipartBody.FORM);
        if (form != null && !form.isEmpty()){
            for (Map.Entry<String, File[]> entry : form.entrySet()) {
                String key = entry.getKey();
                File[] files = entry.getValue();
                for(File file : files) {
                    body.addFormDataPart(key, file.getName(), RequestBody.create(MediaType.parse("application/octet-stream"), file));
                }
            }
        }
        Request.Builder builder = new Request.Builder();
        Request request = builder.url(url).post(body.build()).build();
        OkHttpClient client = new OkHttpClient().newBuilder().build();
        Response response = client.newCall(request).execute();
        if(!response.isSuccessful()) {
            throw new IOException("upload file failure：" + url);
        }
        return response.body().string();
    }

//    public static String postMultipartFormData(String url, Map<String, File[]> form) throws IOException {
//        HttpURLConnection connection = null;
//        logger.info("POST multipart/form-data request: {}", url);
//        String boundary = "----WebKitFormBoundary" + System.currentTimeMillis();
//        try {
//            connection = (HttpURLConnection) new URL(url).openConnection();
//            connection.setRequestMethod("POST");
//            connection.setDoOutput(true);
//            connection.setDoInput(true);
//            connection.setRequestProperty("Cache-Control", "no-cache");
//            connection.setRequestProperty("Connection", "Keep-Alive");
//            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
//            OutputStream os = connection.getOutputStream();
//            for(Entry<String, File[]> entry : form.entrySet()) {
//                String key = entry.getKey();
//                File[] files = entry.getValue();
//                for(File file : files) {
//                    outputFile(boundary, os, key, file);
//                }
//            }
//            outputFoot(boundary, os);
//            String response = StreamUtils.copyToString(connection.getInputStream(), Charset.defaultCharset());
//            logger.info("POST multipart/form-data response: {}", response);
//            return response;
//        } catch (IOException e) {
//            logger.error(url, e);
//            throw e;
//        } finally {
//            if (connection != null) {
//                connection.disconnect();
//            }
//        }
//    }
//    private static void outputFile(String boundary, OutputStream os, String name, File value) throws IOException {
//        String filename = value.getName();
//        InputStream is = new FileInputStream(value);
//        outputStream(boundary, os, name, filename, is);
//        is.close();
//    }
//    private static void outputStream(String boundary, OutputStream os, String name, String filename, InputStream is) throws IOException {
//        os.write(("--" + boundary + "\r\n").getBytes());
//        os.write(("Content-Disposition: form-data;name=\"" + name + "\"; filename=\"" + filename + "\"\r\n").getBytes());
//        os.write(("Content-Type: application/octet-stream\r\n").getBytes());
//        os.write("\r\n".getBytes());
//        StreamUtils.copy(is, os);
//        os.write("\r\n".getBytes());
//        os.flush();
//    }
//    private static void outputFoot(String boundary, OutputStream os) throws IOException {
//        os.write(("--" + boundary + "--" + "\r\n").getBytes());
//        os.flush();
//    }

    private HttpTools() {}
}
